﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Media.Imaging;
#if COUNT_DRAW_OPERATIONS
using BrainTechLLC;
#endif
using System.Windows.Media;
using System.Drawing.Drawing2D;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using System.Runtime.InteropServices;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC.ImageOperatorsNonAForgeDependent
{
    public enum InternalRenderingMethod
    {
        None = 0,
        NearestNeighbor = 1,
        Bilinear = 2,
        Bicubic = 3
    }

    public class RenderSettings
    {
        public InterpolationMode Interpolation;
        public SmoothingMode Smoothing;
        public InternalRenderingMethod RenderingMethod;
        public PixelFormat PixelFormat;
        public bool ForceHighQuality;
    }

    public static partial class ImageOperators
    {
        public static ThreadSafeCounterLong TotalDrawnPixels = new ThreadSafeCounterLong();

#if COUNT_DRAW_OPERATIONS
        public static ThreadSafeCounter DrawImageFailures = new ThreadSafeCounter();        
#endif

        public static Bitmap CloneIfTrue(this Bitmap bm, bool clone)
        {
            if (clone)
            {
                return bm.Clone() as Bitmap;
            }
            else
            {
                return bm;
            }
        }

        public static Bitmap CreateBitmap(this Bitmap source, int maxWidth, int maxHeight, bool maintainAspectRatio, RenderSettings settings)
        {
            int sourceWidth = source.Width;
            int sourceHeight = source.Height;

            return CreateBitmap(source, sourceWidth, sourceHeight, maxWidth, maxHeight, maintainAspectRatio, settings);
        }

        public static Bitmap CreateBitmap(this Bitmap source, int sourceWidth, int sourceHeight, int maxWidth, int maxHeight, bool maintainAspectRatio, RenderSettings settings)
        {
            Bitmap bitmap;

            if (maxWidth == sourceWidth && maxHeight == sourceHeight && source.PixelFormat == settings.PixelFormat)
            {
                bitmap = source.Clone() as Bitmap;
                return bitmap;
            }

            if (maintainAspectRatio)
            {
                double multiplier = Scaling.GetScaledImageDimensions((double)sourceWidth, (double)sourceHeight, (double)maxWidth, (double)maxHeight);

                maxWidth = (int)Math.Floor((double)sourceWidth * multiplier);
                maxHeight = (int)Math.Floor((double)sourceHeight * multiplier);
            }

            return CreateBitmap(source, maxWidth, maxHeight, settings);
        }

        public static Bitmap CreateBitmap(this Bitmap source, int forceWidth, int forceHeight, RenderSettings settings)
        {
            Bitmap bitmap = null;

            switch (settings.RenderingMethod)
            {
                case InternalRenderingMethod.None:
                    {
                        bitmap = DrawBitmap(source, forceWidth, forceHeight, settings);
                        break;
                    }

                case InternalRenderingMethod.NearestNeighbor:
                    {
                        throw new NotSupportedException("Only the AForge-dependent image library CreateBitmap supports this function");
                    }

                case InternalRenderingMethod.Bilinear:
                    {
                        throw new NotSupportedException("Only the AForge-dependent image library CreateBitmap supports this function");
                    }

                case InternalRenderingMethod.Bicubic:
                    {
                        throw new NotSupportedException("Only the AForge-dependent image library CreateBitmap supports this function");
                    }
            }

            return bitmap;
        }

        public static Bitmap DrawBitmap(this Bitmap img, int forceWidth, int forceHeight, RenderSettings settings)
        {
            Bitmap bmOut = null;

            try
            {
                bmOut = new Bitmap(forceWidth, forceHeight, settings.PixelFormat);

                using (Graphics g = Graphics.FromImage(bmOut))
                {
                    if (settings.ForceHighQuality)
                    {
                        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
                        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
                    }
                    else
                    {
                        g.InterpolationMode = settings.Interpolation;
                        g.SmoothingMode = settings.Smoothing;
                    }

                    bool noGo = true;
                    int tries = 0;

                    while (noGo)
                    {
#if TIME_DRAWING_OPERATIONS
                        Timing.BeginTiming();
#endif

                        try
                        {
                            g.DrawImage(img, 0, 0, forceWidth, forceHeight);
                            TotalDrawnPixels.Add(forceWidth * forceHeight);
                            noGo = false;
                        }
                        catch
                        {
#if COUNT_DRAW_OPERATIONS
                            DrawImageFailures.Increment();
#endif

                            if (tries++ > 5)
                                throw;

                            Debug.WriteLine("Drawing error");
                            Thread.Sleep(400);
                        }
                    }
#if TIME_DRAWING_OPERATIONS
                    Timing.EndTiming((d) => AllStats.GetInstance().AddTime("AverageDrawImageTime", d));
#endif
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                bmOut = null;
            }

            return bmOut;
        }
    }
}
